package com.ljx.memorandumMode;

import lombok.Data;

/**
 *
 * 备忘录模式（黑箱）
 *
 * 备忘录角色对发起人对象提供一个宽接口，而为其他对象提供一个窄接口。
 * 在Java语言中，实现双重接口的办法就是将**备忘录类**设计成**发起人类**的内部成员类
 *
 *
 * 备忘录模式
 * 定义：
 * 又叫快照模式，在不破坏封装性的前提下，捕获一个对象的内部状态，
 * 并在该对象之外保存这个状态，以便以后当需要时能将该对象恢复到原先保存的状态
 *
 * 优点：**
 * 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
 * 实现了内部状态的封装。除了创建它的发起人之外，其他对象都不能够访问这些状态信息。
 * 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份，所有状态信息都保存在备忘录中，
 * 并由管理者进行管理，这符合单一职责原则。
 *
 * 缺点：**
 * 资源消耗大。如果要保存的内部状态信息过多或者特别频繁，将会占用比较大的内存资源
 *
 * 使用场景：
 * 需要保存与恢复数据的场景，如玩游戏时的中间结果的存档功能。
 * 需要提供一个可回滚操作的场景，如 Word、记事本、Photoshop，idea
 * 等软件在编辑时按 Ctrl+Z 组合键，还有数据库中事务操作
 *
 * @作者 LJX
 * @日期 2022/12/27 10:24
 */
public class MemorandumBlackBoxTest {

    public static void main(String[] args) {
        System.out.println("================黑箱===============");
        //创建主角
        GameMajor gameMajor = new GameMajor();
        //初始化属性
        gameMajor.init();
        System.out.println("================打BOSS前===============");
        System.out.println(gameMajor.toString());
        //存档
        //创建角色状态管理者
        RoleStateCaretakerMemento roleStateCaretaker = new RoleStateCaretakerMemento();
        roleStateCaretaker.setMemento(gameMajor.saveState());
        System.out.println("===================BOSS战====================");
        gameMajor.challengeBOSS();
        System.out.println(gameMajor.toString());
        System.out.println("===================回档====================");
        gameMajor.retreated(roleStateCaretaker.getMemento());
        System.out.println(gameMajor.toString());
    }

}

/**
 * 标识接口
 */
interface Memento{

}

/**
 * 游戏主角（发起人角色）
 */
@Data
class GameMajor{

    Integer HP;
    Integer ATK;
    Integer DEF;

    //定义成员内部类
    @Data
    private class RoleStateMemento implements Memento{
        Integer HP;
        Integer ATK;
        Integer DEF;

        public RoleStateMemento() {
        }

        public RoleStateMemento(Integer HP, Integer ATK, Integer DEF) {
            this.HP = HP;
            this.ATK = ATK;
            this.DEF = DEF;
        }
    }

    /**
     * 初始化主角属性
     */
    public void init(){
        HP = 100;
        ATK = 100;
        DEF = 100;
    }

    /**
     * 挑战BOSS（失败） 数值清零
     */
    public void challengeBOSS(){
        HP = 0;
        ATK = 0;
        DEF = 0;
    }

    /**
     * 存档
     * @return
     */
    public Memento saveState(){
        return new RoleStateMemento(HP, ATK, DEF);
    }

    /**
     * 回档
     */
    public void retreated(Memento memento){
        RoleStateMemento roleStateMemento = (RoleStateMemento) memento;
        HP = roleStateMemento.HP;
        ATK = roleStateMemento.ATK;
        DEF = roleStateMemento.DEF;
    }

    @Override
    public String toString() {
        return "GameLead{" +
                "HP=" + HP +
                ", ATK=" + ATK +
                ", DEF=" + DEF +
                '}';
    }

}

/**
 * 负责人角色类 `RoleStateCaretakerMemento` 能够得到的备忘录对象是以 `Memento` 为接口的，
 * 由于这个接口仅仅是一个标识接口，因此负责人角色不可能改变这个备忘录对象的内容
 */
@Data
class RoleStateCaretakerMemento{
    private Memento memento;
}
